package com.howie.gulimall.product.exception;

        import com.howie.common.exception.BizCodeEnum;
        import com.howie.common.utils.R;
        import lombok.extern.slf4j.Slf4j;
        import org.springframework.validation.BindingResult;
        import org.springframework.web.bind.MethodArgumentNotValidException;
        import org.springframework.web.bind.annotation.ExceptionHandler;
        import org.springframework.web.bind.annotation.RestControllerAdvice;

        import java.util.HashMap;
        import java.util.Map;

/**
 * @description: 集中处理异常(感知异常)，控制层只要出现了异常，都会执行此类声明的对应处理异常的方法
 * @author: laizhenghua
 * @date: 2020/12/17 11:54
 *
 * 统一异常处理实现步骤：
 * 1、编写异常类处理类，使用@ControllerAdvice注解标记，并指明扫描包路径(com.howie.gulimall.product.controller)
 * 2、使用@ExceptionHandler注解标记方法，指明可以处理的异常类型
 *
 * JSR303分组校验功能(多场景)：
 * 1、给校验注解标记什么情况需要进行校验。@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
 * 2、开启校验功能时，指定校验情况(约束)：@Valid 改为 @Validated({AddGroup.class})
 * 3、默认没有指定分组的校验注解@NotBlank，在分组校验情况(@Validated({UpdateGroup.class}))下不生效！
 *
 * 自定义校验规则：
 * 1、编写一个自定义的校验注解(ListValue)
 * 2、编写一个自定义的校验器(ListValueConstraintValidator)
 * 3、关联自定义的校验器和校验注解(@Constraint(validatedBy = {ListValueConstraintValidator.class}) // 指定校验器，可以指定
 * 多个不同的校验器，适配不同的校验)
 */
// @ResponseBody
// @ControllerAdvice(basePackages = "com.howie.gulimall.product.controller")
@Slf4j
@RestControllerAdvice(basePackages = "com.howie.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
    /*
     * 控制层只要出现了MethodArgumentNotValidException异常，就执行此方法
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handlerValidException(MethodArgumentNotValidException exception){
        log.error("数据校验出现问题{}，异常类型：{}",exception.getMessage(),exception.getClass());

        Map<String,String> errorMap = new HashMap<>();
        // 获取校验的错误结果
        BindingResult result = exception.getBindingResult();
        result.getFieldErrors().forEach((item) -> {
            // 1、获取到错误信息
            String message = item.getDefaultMessage();
            // 2、获取到错误的属性字段
            String field = item.getField();
            errorMap.put(field,message);
        });
        return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),BizCodeEnum.VALID_EXCEPTION.getMessage()).put("error",errorMap);
    }
    /*
     * 如果前面方法不能精确匹配到控制层出现的异常，就执行此方法，此方法可以处理任何异常
     */
    @ExceptionHandler(value = Throwable.class)
    public R handlerException(Throwable throwable){
        log.error("异常信息：{}，异常类型：{}",throwable.getMessage(),throwable.getClass());
        return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(),BizCodeEnum.UNKNOWN_EXCEPTION.getMessage());
    }
}
